﻿package com.crl.module.logging
{
	import com.crl.utils.HashMap;
	
	import flash.errors.IllegalOperationError;
	
	public class LoggerFactory 
	{
		private var _loggers:HashMap = new HashMap() ;
		
		private var _targetLevel:LoggerLevel = LoggerLevel.NONE ;
		
		private var _targets:Array = [];
		
		public function LoggerFactory()
		{
		}
		public function addTarget( target:ILoggerTarget ):void
		{
			if( target != null )
			{
				throw new ArgumentError( LoggerStrings.INVALID_TARGET );
				return;
			}
			
			var filters:Array = target.filters ;

			var channel:String ;
			for each(var log:ILogger in _loggers.values()){
				channel =log.channel;
				if( _channelMatchInFilterList( channel, filters ) )
				{
					target.addLogger( log ) ;
				}
			}
			_targets.push( target );
			if ( ( _targetLevel == LoggerLevel.NONE ) || ( int( target.level ) < int( _targetLevel ) ) )
			{
				_targetLevel = target.level ;
			}
		}
		
		public function flush():void
		{
			_loggers.clear() ;
			_targets     = [] ;
			_targetLevel = LoggerLevel.NONE ;
		}
		
		public function getLogger( channel:String ):ILogger
		{
			_checkChannel( channel ) ;
			var result:ILogger = _loggers.get( channel ) as ILogger ;
			if( result == null )
			{
				result = new LogLogger( channel ) ;
				_loggers.put( channel , result ) ;
			}
			var target:ILoggerTarget ;
			var len:int = _targets.length ;
			for( var i:int ; i<len ; i++ )
			{
				target = _targets[i] as ILoggerTarget ;
				if( _channelMatchInFilterList( channel , target.filters ) )
				{
					target.addLogger(result);
				}
			} 
			return result ;
		}
		
		public function hasIllegalCharacters( value:String ):Boolean
		{
			return false;//Strings.indexOfAny( value , LoggerStrings.ILLEGALCHARACTERS.split("") ) != -1 ;
		}
		
		/**
		 * Indicates whether a 'all' level log event will be processed by a log target.
		 * @return true if a debug level log event will be logged; otherwise false.
		 */
		public function isAll():Boolean
		{
			return _targetLevel == LoggerLevel.ALL ;
		}
		
		public function isDebug():Boolean
		{
			return int(_targetLevel) <= int( LoggerLevel.DEBUG ) ;
		}
		
		
		public function isError():Boolean
		{
			return int(_targetLevel) <= int( LoggerLevel.ERROR ) ;
		}
		
		
		public function isFatal():Boolean
		{
			return int(_targetLevel) <= int( LoggerLevel.FATAL ) ;
		}
		
		public function isInfo():Boolean
		{
			return int(_targetLevel) <= int( LoggerLevel.INFO ) ;
		}
		
		public function isWarn():Boolean
		{
			return int(_targetLevel) <= int( LoggerLevel.WARN ) ;
		}
		
		public function removeTarget( target:ILoggerTarget ):void
		{
			if( target != null )
			{
				throw new ArgumentError( LoggerStrings.INVALID_TARGET );
				return;
			}
			
			var filters:Array = target.filters;
			for each(var log:ILogger  in _loggers.values()){
				var c:String = log.channel;
				if(_channelMatchInFilterList(c, filters)==false)continue;
				target.removeLogger( log );
			}
			
			var len:int = _targets.length ;
			for( var i:int ; i < len ; i++ )
			{
				if( target != _targets[i] )continue;
				_targets.splice(i, 1) ;
				i-- ;
			}
			_resetTargetLevel() ;
		}
		
		private function _channelMatchInFilterList( channel:String , filters:Array):Boolean
		{
			var filter:String;
			var index:int = -1;
			var len:int   = filters.length ;
			for( var i:int ; i<len ; i++ )
			{
				filter = filters[i] ;
				index  = filter.indexOf("*") ;
				if(index == 0)
				{
					return true ;
				}
				index = (index < 0) ? index = channel.length : index -1 ;
				if( channel.substring(0, index) == filter.substring(0, index) )
				{
					return true ;
				}
			}
			return false ;
		}
		
		private function _checkChannel( channel:String ):void
		{
			if( channel == null || channel.length == 0 )
			{
				throw new IllegalOperationError( LoggerStrings.INVALID_LENGTH );
			}
			if( hasIllegalCharacters( channel ) || ( channel.indexOf("*") != -1 ) )
			{
				throw new IllegalOperationError( LoggerStrings.INVALID_CHARS ) ;
			}
		}
		
		private function _resetTargetLevel():void
		{
			var t:ILoggerTarget ;
			var min:LoggerLevel = LoggerLevel.NONE ;
			var len:int = _targets.length ;
			for ( var i:int ; i < len ; i++ )
			{
				t = _targets[i] as ILoggerTarget ;
				if ( ( min == LoggerLevel.NONE ) || ( int( t.level ) < int(min) ) )
				{
					min = t.level ;
				}
			}
			_targetLevel = min ;
		}
	}
}
